home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / i_set.exe / I-SET.C < prev    next >
C/C++ Source or Header  |  1991-09-04  |  20KB  |  761 lines

  1. /* I-SET.c ****************************************************************
  2. A very simple module to allow modification of master
  3. environment under DOS.
  4. External entry points:
  5.  
  6. int iset_load_envstrings (BYTEPTR envblock, char *envstrings[], unsigned *pused)
  7.     Loads the enviromnment in an array of char *. Each entry
  8.     is malloc'd by the function, so it is expected that
  9.     iset_free_envstrings is called after use.
  10.     This routine was originally internal (used by others in this module)
  11.     but it is now public should anyone care. No checking on array
  12.     dimensions!
  13.     If pfree is not NULL, the functions fills it with the number of
  14.     bytes currently used in the environment
  15.  
  16. int iset_free_envstrings (char *envstrings[])
  17.     Frees the copy alloc'd by iset_load_envstrings. It is expected
  18.     that the last valid entry in the array is a zero-length string
  19.     (iset_load_envstrings does this).
  20.  
  21. char *iset_getenv (char *env_par)
  22.     Just like getenv(), only this works on the original environment.
  23.     After use of other functions in this module, the copy which
  24.     is accessed by getenv() could be out of date in respect of
  25.     the master. Used internally also.
  26.  
  27. int iset_set_string (char *env_par, char *env_value)
  28.     Actually a setenv() on the master environment. If a string
  29.     with env_par isn't found, it is added to the environment.
  30.     If env_value is NULL, the string is addedd just like UNIX.
  31.     Note that this routine does attempt to get the strlen()
  32.     of a NULL: in MSC 6.0, the result is 0 and no problem.
  33.     Please look out in other cases.
  34.  
  35. int    iset_append_to_string (char *env_par, char *env_value, int before)
  36.     Adds a new env_value to the end or the beginning
  37.     of the actual value of an environment string, depending
  38.     on before (0: append; 1: insert before).
  39.     If the string didn't exist, it falls
  40.     back to iset_set_string. Otherwise, the string is appended
  41.     with a preceding semi-colon.
  42.  
  43. int iset_cut_string (char *env_par, char *string_to_cut)
  44.     The opposite of iset_append_string. If a string with name
  45.     env_par is found, string_to_cut is searched between pairs
  46.     of semicolons and, if found, the original string is collapsed
  47.     to exclude it. If the string isn't found nothing is done.
  48.  
  49. int iset_delete_string (char *env_par)
  50.     Remove the identified string from the environment. This works
  51.     also on no-value strings which can be produced by
  52.     iset_set_string.
  53.  
  54. int    iset_show_strings (void)
  55.     Will output on stdout the contents of the master environment
  56.     and (little) additional statistics. Useful for seeing variables
  57.     longer than 127 chars, which DOS's set will truncate to 127.
  58.  
  59. This module has been extensively used. Still we don't expect it to
  60. work in every situation! Do complete testings because alteration
  61. of master environment can produce tricky situations to debug.
  62. You can use this source as you like provided you leave this notes
  63. in the module together with the variable id.
  64. Please note that, to assure reentrancy, all functions load a complete
  65. array of pointers (dimension is hardwired) so stack space might
  66. be an issue.
  67.  
  68. I-SET was written by Shari (Davide Migliavacca) of Inferentia S.r.l.,
  69. via Venezian 10, 20123 Milano ITALY.
  70. Tel. +39.2.266680568.
  71. CompuServe 100016,2335
  72. **********************************************************/
  73.  
  74. /* You can't remove this lines */
  75. #define VERSIONE    "3.53"
  76. static const char *id= "I-Set " VERSIONE " " __DATE__ " " __TIME__ " Created by Shari CIS 100016,2335";
  77. /*******************************/
  78.  
  79.  
  80.  
  81. #include <stdio.h>
  82. #include <stdlib.h>
  83. #include <string.h>
  84. #include <dos.h>
  85. #include <options.h>
  86.  
  87.  
  88. /* Should DOS grow beyond this limit, you may put
  89.    a version checking function instead of this macro */
  90. #define dos_max_pathvar_length()    127
  91. int    iset_check_length(char *env_par, int len);
  92.  
  93.  
  94. typedef unsigned char BYTE;
  95. typedef unsigned int WORD;
  96. typedef unsigned long DWORD;
  97. typedef BYTE _far * BYTEPTR;
  98. typedef WORD _far * WORDPTR;
  99. typedef DWORD _far *DWORDPTR;
  100. typedef void _far *FP;
  101.  
  102.  
  103.  
  104. #define MK_FP(seg, off)        ((FP)((DWORD)(((WORD)(off)) | ((DWORD)((WORD)(seg))) << 16 )))
  105.  
  106. #define    INT20h    0xCD20
  107.  
  108. static char terminating_null = '\0';
  109. union REGS regs;
  110.  
  111. typedef struct tagPSP {
  112.     WORD        int20;            /* must be 0xCD20 */
  113.     WORD        alloc_end_seg;        /* segment, end of allocation block */
  114.     BYTE        reserved_1;        
  115.     BYTE        far_call;            /* call far ... next field */
  116.     DWORD    DOS_dispatcher;    /* address of DOS dispatcher */
  117.     DWORD    termination_handler;/* int 22h contents */
  118.     DWORD    ctrl_c_handler;    /* int 23h contents */
  119.     DWORD    crit_err_handler;    /* int 24h contents */
  120.     WORD        parent_PSP;        /* UNDOCUMENTED */
  121.     BYTE        JFT[20];            /* Job file table: UNDOCUMENTED */
  122.     WORD        env_seg;            /* segment of environment block */
  123.     DWORD    reserved_2;        
  124.     WORD        max_opens;        /* # of entries in JFT: UNDOCUMENTED */
  125.     DWORD    actual_JFT;        /* Address of actual JFT: UNDOCUMENTED */
  126.     BYTE        reserved_3[36];
  127.     BYTE        FCB_1[16];        /* Default FCB #1 */
  128.     BYTE        FCB_2[20];        /* Default FCB #2 (overlaid by 1 if used)*/
  129.     BYTE        command_tail[128];    /* command tail and DTA */
  130. } PSP;
  131.  
  132.  
  133. typedef struct tagMCB {
  134.     BYTE        type;
  135.     WORD        owner;    /* PSP of owner */
  136.     WORD        size;
  137.     BYTE        reserved[3];
  138.     BYTE        dos4[8];
  139. } MCB;
  140.  
  141.  
  142. static unsigned env_size(WORD envseg)
  143. {
  144.     unsigned envsize;
  145. _asm {
  146.         mov    ax,envseg             /* get segment of env */
  147.         dec    ax                  /* back up to MCB */
  148.         mov    es,ax
  149.         mov    ax,es:[0003h]       /* get size in grafs */
  150.         mov    envsize, ax
  151.     }
  152.     return envsize << 4;        /* multiply by paragraph size */
  153. }
  154.  
  155.  
  156. /* determines if seg is really a psp:
  157.     1)    at seg-1 there must be a DOS MCB whose owner is seg
  158.     2)    the first two bytes in seg must be 0xCD 0x20 (int 20h)
  159.   From "Undocumented DOS" by Andrew Schulman, Byte  Vol. 16, #3 (March 1991)
  160. */
  161. static int is_psp (WORD seg)
  162. {
  163.     return ((((MCB _far *) MK_FP(seg-1, 0))->owner == seg) &&
  164.            (*((WORD _far *) MK_FP(seg, 0)) == INT20h));
  165. }
  166.  
  167.  
  168. static WORD get_shell_psp_seg()
  169. {
  170.     PSP    _far *my_psp;
  171.     PSP    _far *parent_psp;
  172.  
  173.     /* get PSP address (int 21h fun 62h, DOS >= 3.0) */
  174.  
  175.     regs.h.ah = 0x62;
  176.  
  177.     intdos (®s, ®s);
  178.     
  179.     /* bx contains segment of PSP */
  180.  
  181.     my_psp = (PSP _far *)MK_FP(regs.x.bx, 0);
  182.  
  183.     do {
  184.         parent_psp = (PSP _far *)MK_FP(my_psp->parent_PSP, 0);
  185.         my_psp = parent_psp;
  186.     } while (parent_psp->parent_PSP != FP_SEG(parent_psp));
  187.  
  188.  
  189.     return FP_SEG(parent_psp);
  190.  
  191. static BYTEPTR get_envblock ()
  192. {
  193.     WORD    shell_psp_seg;
  194.     PSP _far *shell_psp;
  195.  
  196.     shell_psp_seg = get_shell_psp_seg();
  197.     shell_psp = (PSP _far *) MK_FP(shell_psp_seg, 0);
  198.  
  199.     return ((BYTEPTR) MK_FP(shell_psp->env_seg, 0));
  200. }
  201.  
  202. int iset_load_envstrings (BYTEPTR envblock, char *envstrings[], unsigned *pused)
  203. {
  204.     char _far *envpointer = (char _far *)envblock;
  205.     size_t len;
  206.     int    i = 0;
  207.  
  208.     while (*envpointer != '\0') {
  209.         len = _fstrlen (envpointer);
  210.         envstrings[i] = (char *) malloc (len + 1);
  211.         _fstrcpy ((char _far *) envstrings[i], envpointer);
  212.         envpointer += (len + 1);
  213.         ++i;
  214.     }
  215.     envstrings[i] = &terminating_null;
  216.     if (pused != (unsigned *)NULL)
  217.         *pused = (unsigned) (envpointer - envblock);
  218.  
  219.     return i;
  220. }
  221.  
  222. int iset_free_envstrings (char *envstrings[])
  223. {
  224.     int i = 0;
  225.  
  226.     while (envstrings[i][0] != '\0')
  227.         free (envstrings[i++]);
  228.  
  229.     return 0;
  230. }
  231.  
  232.     
  233. static int    search_string (char *string, char *array[])
  234. {
  235.     int i = 0;
  236.  
  237.     while (array[i][0] != '\0')
  238.     {
  239.         if (!strnicmp(array[i], string, strlen(string)))
  240.             return i;
  241.         else
  242.             i++;
  243.     }
  244.  
  245.     return -1;
  246. }
  247.  
  248.  
  249. /* works on original environment, which may be different
  250.    from our copy because of other iset_... function calls */
  251. char *iset_getenv (char *env_par)
  252. {
  253.     char *env_strings[128];
  254.     BYTEPTR    envblock;
  255.     int    maxstring;
  256.     int    i;
  257.     static char env_name[128];
  258.     static char env_value[256];
  259.     char    *return_this = NULL;
  260.     char    *equal;
  261.  
  262.     envblock = get_envblock();
  263.     maxstring = iset_load_envstrings (envblock, env_strings, NULL);
  264.  
  265.     env_value[0] = '\0';
  266.     for (i = 0; i < maxstring; i++) {
  267.         equal = strchr(env_strings[i], '=');
  268.         if (equal != NULL) {
  269.             strncpy (env_name, env_strings[i], equal - env_strings[i]);
  270.             env_name[equal - env_strings[i]]='\0';
  271.         }
  272.         else
  273.             strcpy (env_name, env_strings[i]);
  274.